package com.aliyun.heiyu.powermaster.server.strategy;

import com.aliyun.heiyu.common.util.HttpUtil;
import com.aliyun.heiyu.common.util.PropertiesUtil;
import com.aliyun.heiyu.common.util.StringUtil;
import com.aliyun.heiyu.powermaster.proto.PowerStrategy;
import com.aliyun.heiyu.powermaster.proto.StrategyAction;
import com.aliyun.heiyu.powermaster.server.MasterConstant;
import com.aliyun.heiyu.powermaster.server.SetPowerEntity;
import com.aliyun.heiyu.powermaster.server.dao.CapFminDao;
import com.aliyun.heiyu.powermaster.server.dao.DeviceServerDao;
import com.aliyun.heiyu.powermaster.server.dao.StateGridCapTaskItemDao;
import com.aliyun.heiyu.powermaster.server.dao.entity.CapFminEntity;
import com.aliyun.heiyu.powermaster.server.dao.entity.DeviceCommonEntity;
import com.aliyun.heiyu.powermaster.server.dao.entity.StateGridCapTaskItemEntity;
import com.aliyun.heiyu.powermaster.server.dao.entity.StrategyActionHistoryEntity;
import com.aliyun.heiyu.powermaster.server.dao.impl.CapFminImpl;
import com.aliyun.heiyu.powermaster.server.dao.impl.DeviceServerDaoImpl;
import com.aliyun.heiyu.powermaster.server.dao.impl.StateGridCapTaskItemImpl;
import com.aliyun.heiyu.powermaster.server.manager.*;
import com.aliyun.heiyu.powermaster.server.strategy.action.PowerOffAction;
import org.apache.http.client.utils.URIBuilder;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class StrategyActor {
    private static final Logger logger = LoggerFactory.getLogger(StrategyActor.class);
    private static double FMIN_RATE = 0.75;
    private static double CAP_RATE = 0.75;
    private int port;

    private ThunderManager thunderManager;
    private DeviceManager deviceManager;
    private CapFminDao stateGridDao;
    private PowerOffAction powerOffAction;
    private StrategyManager strategyManager;
    private DeviceServerDao deviceServerDao=new DeviceServerDaoImpl();


    private Map<String, SetPowerEntity> sn2SetPowerEntity = new ConcurrentHashMap<>();

    public StrategyActor() {
        this.strategyManager = StrategyManager.getInstance();
        double fminRate = StringUtil.convertDouble(PropertiesUtil.getValue("aiControllerConfig.properties", "fmin_rate"));
        double capRate = StringUtil.convertDouble(PropertiesUtil.getValue("aiControllerConfig.properties", "cap_rate"));
        FMIN_RATE = fminRate == 0 ? FMIN_RATE : fminRate;
        CAP_RATE = capRate == 0 ? CAP_RATE : capRate;
        FMIN_RATE = Double.valueOf(PropertiesUtil.getValue("aiControllerConfig.properties", "fmin_rate"));
        CAP_RATE = Double.valueOf(PropertiesUtil.getValue("aiControllerConfig.properties", "cap_rate"));
        port = Integer.parseInt(PropertiesUtil.getValue("serverIp.properties", "thunderPort"));
        stateGridDao = new CapFminImpl();
        powerOffAction = PowerOffAction.getInstance();
        thunderManager = new ThunderManagerImpl();
        deviceManager = DeviceManagerImpl.getInstance();
    }

    /**
     * 调用thunder提供的接口，进行capping、uncapping
     */
    public void capping(Map<String, StrategyAction> sn2Action) {
        logger.debug(PowerStrategy.CAPPING_POWER.name() + "...");
        Map<String, SetPowerEntity> setPowerMap = new HashMap<>();
        for (String sn : sn2Action.keySet()) {
            StrategyAction action = sn2Action.get(sn);
            DeviceCommonEntity deviceCommon = deviceManager.findOneDeviceCommon(sn);
            if (!"server".equals(deviceCommon.getType())) {
                continue;
            }
            SetPowerEntity setPowerEntity = new SetPowerEntity();
            setPowerEntity.setServerIp(deviceCommon.getIp());
            //判断需要capping，并设置具体值
            if (PowerStrategy.DEFAULT.name().equals(action.getActionName())){
                continue;
            }
            if (PowerStrategy.CAPPING_POWER.name().equals(action.getActionName())) {
                setPowerEntity.setCapAction(true);
                //freqLimit
                int fmin = StringUtil.convertInt(action.getFmin());
                int freqLimit;
                if (fmin == 0) {
                    CapFminEntity entity = stateGridDao.findOne(deviceCommon.getDevice_id());
                    if (entity != null) {
                        freqLimit = entity.getFmin() * 1000;//Mhz 转 khz
                    } else {
                        freqLimit = 1800 * 1000;//默认1800Mhz
                    }
                } else {
                    freqLimit = fmin * 1000; //Mhz 转 khz
                }
                setPowerEntity.setFreqLimit(freqLimit);
                //powerLimit
                int powerLimit;
                if ("W".equals(action.getCapType())) {
                    powerLimit = StringUtil.convertInt(action.getCapTo());
                } else {// 默认：%, 通过设备的额定功率计算capping的PowerLimit值，并设置
                    int capRate = StringUtil.convertInt(action.getCapTo());
                    powerLimit = (int)StringUtil.convertDouble(deviceCommon.getRated_power()) * capRate / 100;
                }
                setPowerEntity.setPowerLimit(powerLimit);
            } else {
                //uncapping
                setPowerEntity.setCapAction(false);
            }

            setPowerMap.put(sn, setPowerEntity);
            logger.debug("capAction: {}, serverIp: {}, equipmentNumber: {}, fmin: {} Mhz, powerLimit:{}W", setPowerEntity.isCapAction(),
                setPowerEntity.getServerIp(), sn, setPowerEntity.getFreqLimit() / 1000, setPowerEntity.getPowerLimit() );
        }

        doCapping(setPowerMap);
    }

    private boolean compareCappingStatus(String sn, SetPowerEntity setPowerEntity){
        StateGridCapTaskItemDao dao = new StateGridCapTaskItemImpl();
        DeviceCommonEntity device = deviceManager.findOneDeviceCommon(sn);
        if (device == null || StringUtil.isEmpty(device.getIp())) {
            return true;
        }
        String ip = device.getIp();
        StateGridCapTaskItemEntity lastOne = dao.findLastOne(ip);
        if (lastOne == null && setPowerEntity.isCapAction()) {
            return false;
        } else if(lastOne == null && !setPowerEntity.isCapAction()){
            return true;
        }
        String param = lastOne.getParam();
        if (param == null || "-1".equals(param)) {
            if(!setPowerEntity.isCapAction()){
                return true;
            }

            return false;
        } else {
            if(!setPowerEntity.isCapAction()){
                return false;
            }
            //todo 具体判断capping动作参数
            return true;
        }

    }

    private Boolean doCapping(Map<String, SetPowerEntity> setPowerEntityMap) {
        Collection<SetPowerEntity> listSetPower = new ArrayList<>(setPowerEntityMap.values());
        if (listSetPower.size() <= 0) {
            return true;
        }
        Set<String> keySet = setPowerEntityMap.keySet();
        //todo 更换thunder进行动作
        //通过http方式调用thunder接口：/stateGrid/powerData
        String host = PropertiesUtil.getValue("serverIp.properties", "setPowerUrl");
        String json = new JSONArray(listSetPower).toString();
        JSONObject jsonObject = HttpUtil.postRequest(json, host);
        logger.debug("发出请求,host= {} json == {}", host, json);
        if (jsonObject == null || !jsonObject.getBoolean("success")) {
            logger.error("访问服务器失败:");
            return false;
        }
        //睡眠1s
        try {
            Thread.sleep(50000L);
            //检查并记录当前状态
            for (String sn : keySet) {
                Boolean statusOfCapping = thunderManager.getStatusOfCapping(sn);
                SetPowerEntity setPowerEntity = setPowerEntityMap.get(sn);
                boolean capAction = setPowerEntity.isCapAction();
                if (capAction && (statusOfCapping == null || statusOfCapping)) {
                    record(sn, true, MasterConstant.CAPPING, 1);
                    //capping,关闭turbo
                    operateTurbo(2, setPowerEntity.getServerIp());
                } else if (capAction && (statusOfCapping == null || !statusOfCapping)) {
                    record(sn, true, MasterConstant.CAPPING, 2);
                } else if (!capAction && (statusOfCapping == null || !statusOfCapping)) {
                    record(sn, false, MasterConstant.CAPPING, 1);
                    operateTurbo(1, setPowerEntity.getServerIp());
                } else if (!capAction && (statusOfCapping == null || statusOfCapping)) {
                    record(sn, false, MasterConstant.CAPPING, 2);
                }
                logger.debug("record {} capping action history", sn);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return true;
    }



    public void aiCapping(Map<String, StrategyAction> sn2Action) {
        logger.debug(PowerStrategy.CAPPING_POWER.name() + "...");
        Map<String, SetPowerEntity> setPowerMap = new HashMap<>();
        for (String sn : sn2Action.keySet()) {
            StrategyAction action = sn2Action.get(sn);
            DeviceCommonEntity deviceCommon = deviceManager.findOneDeviceCommon(sn);
            if (deviceCommon == null || !"server".equals(deviceCommon.getType())) {
                continue;
            }

            SetPowerEntity setPowerEntity = new SetPowerEntity();
            setPowerEntity.setServerIp(deviceCommon.getIp());
            SetPowerEntity entity1 = sn2SetPowerEntity.get(sn);
            //判断需要capping，并设置具体值
            if (PowerStrategy.DEFAULT.name().equals(action.getActionName())){
                continue;
            }
            if (PowerStrategy.CAPPING_POWER.name().equals(action.getActionName())) {
                setPowerEntity.setCapAction(true);

                //freqLimit
                int freqLimit = 0;
                if(!StringUtil.isEmpty(action.getFmin())){
                    int fmin = StringUtil.convertInt(action.getFmin());
                    freqLimit = fmin * 1000;
                } else {
                    double fminRate = FMIN_RATE;
                    double ratedFreq = 2500;
                    freqLimit = (int) (fminRate * ratedFreq) * 1000;
                }

                setPowerEntity.setFreqLimit(freqLimit);
                //powerLimit
                int powerLimit = 0;
                if(!StringUtil.isEmpty(action.getCapTo())){
                    if ("W".equals(action.getCapType())) {
                        powerLimit = StringUtil.convertInt(action.getCapTo());
                    } else {// 默认：%, 通过设备的额定功率计算capping的PowerLimit值，并设置
                        int capRate = StringUtil.convertInt(action.getCapTo());
                        powerLimit = (int)StringUtil.convertDouble(deviceCommon.getRated_power()) * capRate / 100;
                    }
                } else {
                    double capRate = CAP_RATE;
                    double ratedPower = StringUtil.convertDouble(deviceCommon.getRated_power());
                    powerLimit = (int) (capRate * ratedPower);
                }

                setPowerEntity.setPowerLimit(powerLimit);
            } else {
                setPowerEntity.setCapAction(false);
            }
            sn2SetPowerEntity.put(sn, setPowerEntity);//capping动作记录
            if(entity1 == null){
                if(!setPowerEntity.isCapAction()){
                    continue;
                }
            }
            if(entity1 != null){
                if(!entity1.isCapAction() && !setPowerEntity.isCapAction()){
                    continue;
                }
                if(entity1.equals(setPowerEntity)){
                    continue;
                }
            }
            setPowerMap.put(sn,setPowerEntity);
            logger.debug("capAction: {}, serverIp: {}, equipmentNumber: {}, fmin: {} Mhz, powerLimit:{}W", setPowerEntity.isCapAction(),
                setPowerEntity.getServerIp(), sn, setPowerEntity.getFreqLimit() / 1000, setPowerEntity.getPowerLimit() );
        }

        doCapping(setPowerMap);
    }

    public void dvfs(Map<String, StrategyAction> sn2Action) {
        logger.debug(PowerStrategy.DVFS.name() + "...");
        for (String sn : sn2Action.keySet()) {
            StrategyAction action = sn2Action.get(sn);
            DeviceCommonEntity deviceCommon = deviceManager.findOneDeviceCommon(sn);
            if (!"server".equals(deviceCommon.getType())) {
                continue;
            }

            if (PowerStrategy.DEFAULT.name().equals(action.getActionName())){
                continue;
            }
            if (PowerStrategy.DVFS.name().equals(action.getActionName())) {
                thunderManager.operateDvfs(1, sn);

            } else if (PowerStrategy.NONE.name().equals(action.getActionName())) {
                thunderManager.operateDvfs(2, sn);

            }
            logger.debug("{} dvfs action", sn);
        }
        //睡眠1s
        try {
            Thread.sleep(2000L);
            //检查并记录当前状态
            for (String sn : sn2Action.keySet()) {
                StrategyAction action = sn2Action.get(sn);
                if (PowerStrategy.DEFAULT.name().equals(action.getActionName())){
                    continue;
                }
                Boolean statusOfDvfs = thunderManager.getStatusOfDvfs(sn);
                if (PowerStrategy.DVFS.name().equals(action.getActionName()) && (statusOfDvfs == null || statusOfDvfs)) {
                    record(sn,true,MasterConstant.DVFS,1);
                } else if (PowerStrategy.DVFS.name().equals(action.getActionName()) && (statusOfDvfs == null || !statusOfDvfs)) {
                    record(sn,true,MasterConstant.DVFS,2);
                } else if (PowerStrategy.NONE.name().equals(action.getActionName()) && (statusOfDvfs == null || !statusOfDvfs)) {
                    record(sn,false,MasterConstant.DVFS,1);
                } else if (PowerStrategy.NONE.name().equals(action.getActionName()) && (statusOfDvfs == null || statusOfDvfs)) {
                    record(sn,false,MasterConstant.DVFS,2);
                }
                logger.debug("record {} dvfs action history", sn);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void cstate(Map<String, StrategyAction> sn2Action) {
        logger.debug(PowerStrategy.CSTATE.name() + "...");
        for (String sn : sn2Action.keySet()) {
            StrategyAction action = sn2Action.get(sn);
            DeviceCommonEntity deviceCommon = deviceManager.findOneDeviceCommon(sn);
            if (!"server".equals(deviceCommon.getType())) {
                continue;
            }
            if (PowerStrategy.DEFAULT.name().equals(action.getActionName())){
                continue;
            }
            if (PowerStrategy.CSTATE.name().equals(action.getActionName())) {
                thunderManager.operateCstate(1, sn);

            } else if (PowerStrategy.NONE.name().equals(action.getActionName())) {
                thunderManager.operateCstate(2, sn);

            }
            logger.debug("{} c-state action ", sn);
        }
        //睡眠1s
        try {
            Thread.sleep(2000L);
            //检查并记录当前状态
            for (String sn : sn2Action.keySet()) {
                StrategyAction action = sn2Action.get(sn);
                if (PowerStrategy.DEFAULT.name().equals(action.getActionName())){
                    continue;
                }
                Boolean statusOfCstate = thunderManager.getStatusOfCstate(sn);
                if (PowerStrategy.CSTATE.name().equals(action.getActionName()) && (statusOfCstate == null || statusOfCstate)) {
                    record(sn,true,MasterConstant.CSTATE,1);
                } else if (PowerStrategy.CSTATE.name().equals(action.getActionName()) && (statusOfCstate == null || !statusOfCstate)) {
                    record(sn,true,MasterConstant.CSTATE,2);
                } else if (PowerStrategy.NONE.name().equals(action.getActionName()) && (statusOfCstate == null || !statusOfCstate)) {
                    record(sn,false,MasterConstant.CSTATE,1);
                } else if (PowerStrategy.NONE.name().equals(action.getActionName()) && (statusOfCstate == null || statusOfCstate)) {
                    record(sn,false,MasterConstant.CSTATE,2);
                }
                logger.debug("record {} cstate action history", sn);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void powerOff(Map<String, StrategyAction> sn2Action) {
        logger.debug(PowerStrategy.POWER_OFF.name() + "...");
        try {
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (String sn : sn2Action.keySet()) {
            String actionName = sn2Action.get(sn).getActionName();
            if (PowerStrategy.DEFAULT.name().equals(actionName)){
                continue;
            }
            if (PowerStrategy.POWER_OFF.name().equals(actionName)) {
                logger.debug("poweroff intpool start ---- sn ==  {}" , sn);
                powerOffAction.inPool(sn);
                record(sn,true,MasterConstant.POWEROFF,1);
            } else {
                logger.debug("poweroff outpool start ---- sn ==  {}" , sn);
                powerOffAction.outPool(sn);
                record(sn,false,MasterConstant.POWEROFF,1);
            }
        }
    }

    public Boolean operateTurbo(int action, String ip) {
        logger.info("设备IP == "+ip+" capping 操作携带控制turbo ");
        String host = PropertiesUtil.getValue("serverIp.properties", "serverIp");
        try {
            URIBuilder uriBuilder = new URIBuilder().setScheme("http")
                .setHost(host)
                .setPort(port)
                .setPath("/stateGrid/turbo/setTurbo")
                .setParameter("serverIp", ip);
            if (action == 1) {
                //打开
                uriBuilder.setParameter("enable","1");
            } else if (action == 2) {
                uriBuilder.setParameter("enable","0");
            }
            JSONObject jsonObject = HttpUtil.getRequest(uriBuilder.build());
            logger.debug("url == {}",uriBuilder.build());
            if (jsonObject == null || !jsonObject.getBoolean("success")) {
                logger.error("访问服务器失败,");
                return null;
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return true;
    }

    /**记录*/
    private void record(String sn, boolean switchOn, String analyzeType, int status){
        StrategyActionHistoryEntity entity = new StrategyActionHistoryEntity();
        entity.setActionName(convertAnalyzeType2ActionName(analyzeType));
        entity.setDeviceID(sn);
        entity.setStatus(status);
        entity.setSwitchOn(switchOn);
        entity.setTime(new Timestamp(System.currentTimeMillis()));
        strategyManager.insertActionHistory(entity);
    }

    private String convertAnalyzeType2ActionName(String analyzeType){
        if(MasterConstant.AI_CAPPING.equals(analyzeType)){
            return MasterConstant.CAPPING;
        }else if(MasterConstant.AI_DVFS.equals(analyzeType)){
            return MasterConstant.DVFS;
        }else if(MasterConstant.AI_CSTATE.equals(analyzeType)){
            return MasterConstant.CSTATE;
        }else if(MasterConstant.AI_POWEROFF.equals(analyzeType)){
            return MasterConstant.POWEROFF;
        }else if(MasterConstant.CAPPING.equals(analyzeType)){
            return MasterConstant.CAPPING;
        }else if(MasterConstant.POWEROFF.equals(analyzeType)){
            return MasterConstant.POWEROFF;
        }else if(MasterConstant.DVFS.equals(analyzeType)){
            return MasterConstant.DVFS;
        }else if(MasterConstant.CSTATE.equals(analyzeType)){
            return MasterConstant.CSTATE;
        } else {
            logger.error("cannot find matched analyzeType in convertAnalyzeType2ActionName()");
            return "";
        }
    }

}
